<script setup lang="ts">
import {answer, qaArr, question} from "@/store/songStore";
import {nextTick, ref} from "vue";
import {currentApiKey, currentChatUrl} from "@/store/chatApiStore";
import router from "@/Router";
import ChatSettingSvg from "@/svg/ChatSettingSvg.vue";
import SendSvg from "@/svg/sendSvg.vue";
import LoadingSvg from "@/svg/LoadingSvg.vue";
import CarbonKnowSvg from "@/svg/CarbonKnowSvg.vue";
import {useRoute} from "vue-router";
import {addUserChat, findAllUserChatByAccountName} from "@/Network/chatApi";


let showCarbonTipInfo = ref(true)
let preQArr = ref(["什么是碳资产，如何定义它？","为什么要管理碳资产","碳资产发展对国家的影响","碳资产在生活中的例子","碳服务有什么","如何管理碳资产",])
let waitingSign = ref(false)

let tmpIndex = window.location.href.indexOf("?")+7 //从=后面开始算
//这里为了方便，直接 先统一设成admin的问答，就不用开其他服务了。
// let accountName = window.location.href.slice(tmpIndex)
// localStorage.setItem("accountName",accountName)
let accountName = "admin"
findAllUserChatByAccountName(accountName).then(res=>{
  let tmpArr = res.data
  // console.log(tmpArr)
  for(let i=0;i<tmpArr.length;i++){
    // console.log(tmpArr[i].question)
    let userWord = {
      person:"user",
      words:tmpArr[i].question
    }
    qaArr.value.push(userWord)
    let gptWord = {
      person:"gpt",
      words:tmpArr[i].answer
    }
    qaArr.value.push(gptWord)
  }
})

//在界面渲染之前，应该把数据获取到，根据用户名在数据库中查找相关信息 => 整理成 qaArr形式的字典才行
//然后就用这个字典去展示
//每一次点击 发送问题，就需要向数据库发送数据进行存储，当然qaArr也要增加相应数据，这样就不用重复读取数据了。

nextTick(() => {
  document.getElementById(qaArr.value.length-1)
      .scrollIntoView({
        alignToTop:false,
        behavior:"smooth",
      })
})

function goToButton(){
  //nextTick 等界面的dom元素都渲染完成后再执行
  nextTick(()=>{
    document.getElementById((qaArr.value.length-1))
        .scrollIntoView({
          alignToTop:false,
          behavior:"smooth",
        })
  })
}

function addAndScroll(){
  let temp = {words:"test", person:"gpt"}
  qaArr.value.push(temp)
  goToButton()
}

async function streamFetchChineseChat(){
  showCarbonTipInfo.value = false;
  let userWord = {
    person:"user",
    words:question.value
  }
  qaArr.value.push(userWord)
  waitingSign.value = true
  goToButton()

  try{
    // 发送请求
    let response = await fetch(currentChatUrl.value,
        {
          method: "post",
          responseType: "stream",
          headers: {
            "Authorization": "Bearer " + currentApiKey.value,
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            "model": "gpt-3.5-turbo",
            "messages": [{"role": "user", "content": JSON.stringify(question.value)+" (中文回答且不能超过50字)"}],
            "stream":true
          }),
        }
    );

    // ok字段判断是否成功获取到数据流
    if (!response.ok) {
      console.log("Network response was not ok");
    }
    // 用来获取一个可读的流的读取器（Reader）以流的方式处理响应体数据
    const reader = response.body.getReader();
    // 将流中的字节数据解码为文本字符串
    const textDecoder = new TextDecoder();
    let result = true;
    let sqlValue = ''
    let count = 0

    while (result) {
      // done表示流是否已经完成读取  value包含读取到的数据块
      const { done, value } = await reader.read();
      if (done) {
        result = false;
        break;
      }
      // 拿到的value就是后端分段返回的数据，大多是以data:开头的字符串
      // 需要通过decode方法处理数据块，例如转换为文本或进行其他操作
      textDecoder
          .decode(value)
          .split("\n")
          .forEach((val) => {
            if (!val) return;
            try {
              // 后端返回的流式数据一般都是以data:开头的字符，排除掉data:后就是需要的数据,并将其序列化JSON。parse方便操作键值
              // 具体返回结构可以跟后端约定
              let text = val?.replace("data:", "") || ""
              // console.log(text)
              let singleAns = JSON.parse(text)
              // console.log( "输出返回的:"+singleAns.choices[0].delta.content);
              if(singleAns.choices[0].finish_reason !="stop"){//未结束时为null
                sqlValue += singleAns.choices[0].delta.content;

                answer.value = sqlValue
                let gptWord = {
                  person:"gpt",
                  words:answer.value
                }
                if(count==0){
                  waitingSign.value = false
                  qaArr.value.push(gptWord)
                  count +=1
                }else{
                  qaArr.value.splice(qaArr.value.length-1,1,gptWord)
                }

                goToButton()
              }
            } catch (err) {}
          });
    }
    await addUserChat(accountName,question.value,answer.value)
    question.value = ""
    // console.log('addUserChat')
  } catch(err) {}
}
function clickedPreQ(preQ:string){
  question.value = preQ
  // newToQuestion()
  // newToQuestion()
  streamFetchChineseChat()
}
function toSetting(){
  router.push("/chat_setting")
}

function getUserCss(i){
  let v = [];
  if (i.person == "user") {
    v.push("userTalkSpan");

  }else {
    v.push("gptTalkSpan");

  }
  return v;
}

</script>

<template>
  <div class="w-full h-full flex flex-col">
<!--    el_scrollbar最好放在外层，否则template-if-else的时候容易出现（因高度混乱？导致的）滚动异常-->
    <el-scrollbar class="grow">
      <template v-if="showCarbonTipInfo==true">
        <div class="flex justify-center items-center mt-40">
          <div class="flex flex-col w-88% h-full items-center gap-4">
            <carbon-know-svg class="h-32 w-32 text-green-5"></carbon-know-svg>
            <p class="text-7">你好，我是碳知道</p>
            <p class="w-150 text-center">我是基于深度学习和自然语言处理技术的生成式AI产品，可以帮您解答碳资产领域相关的问题，提高您的工作学习效率。</p>
            <div class="mt-4 flex w-full justify-start items-start">
              <div class="text-gray-4 select-none">您可以试试这样问我</div>
            </div>
            <div class="w-full grid grid-cols-2 gap-4">
              <div v-for="ele in preQArr">
                <div class="bg-white p-2 rounded-lg hover:bg-green-4 hover:text-white cursor-pointer"
                     @click="clickedPreQ(ele)"
                >
                  {{ele}}
                </div>
              </div>
            </div>

          </div>
        </div>
      </template>
      <template v-else>
        <div v-for="(i, index) in qaArr"
             :class="i.person=='user'?'userTalk':'gptTalk'"
             class="w-full   "
             :id="index"
        >
          <div v-html="i.words" class=" p-3 rounded-t-lg text-5 "
               :class="getUserCss(i)">
          </div>
        </div>
        <div v-show="waitingSign">
          <div class="gptTalk w-full"
          >
            <div class="gptTalkSpan p-3 rounded-t-lg">
              <loading-svg class="animate-spin text-green-5 w-6 h-6  "></loading-svg>
            </div>
          </div>
        </div>
      </template>

    </el-scrollbar>
    <div class="search h-12     flex justify-center items-center gap-4 mx-5 mb-5">
      <button class=" h-13 w-13 border-3 border-white bg-green-4 rounded-full
            hover:bg-green-5 flex justify-center items-center"
              @click="toSetting"
      >
        <chat-setting-svg class="w-8 h-8 text-white"></chat-setting-svg>
      </button>

      <input class=" grow   bg-white  outline-none h-12 rounded-xl border-2
      border-gray-3  pl-5 hover:border-green-4 hover:border-3
      text-gray-5 text-5"
             placeholder="请向我提问吧 ^_^"
             v-model="question"
             @keyup.enter="streamFetchChineseChat"
      />
      <button class="h-13 w-13 border-3 border-white bg-green-4 rounded-full
      hover:bg-green-5 flex justify-center items-center"
              @click="streamFetchChineseChat"
      >
        <send-svg class="w-8 h-8 mr-0.7"></send-svg>
      </button>
    </div>

  </div>
</template>

<style scoped>
.userTalk{
  @apply mb-3  flex justify-end items-start ;
}

.gptTalk{
  @apply pl-6 mb-3  flex justify-start items-start ;
}

.userTalkSpan{
  @apply mr-5  bg-green-5 ml-100  mb-4 border-3 text-white  flex justify-end items-center rounded-l-lg break-all break-words;
}

.gptTalkSpan{
  @apply  bg-white border-3  mr-100 mb-4  text-gray-7   flex justify-start items-center rounded-r-lg break-all break-words ;
}
</style>